﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Diagnostics;

namespace SharpMap.Control
{
    class RectangleTracker
    {
        private UserControl _uc = null;
        private Point _mouse_start;
        private Point _mouse_moving;
        protected Point _oldP1 = new Point(0, 0);
        protected Point _oldP2 = new Point(0, 0);

        private bool _is_tracking = false;

        private Image _image = null;
        protected Graphics _pg1 = null;

        protected TextureBrush _staticTextureBrush = null;
        protected Pen _staticPenRubout = new Pen(Color.Red, 3);

        private int _width = 1;
        private Color _color = Color.FromArgb(255, 0, 0, 0);

        private Rectangle _rect;

        #region Win32 Function Declare
        [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
        private static extern bool BitBlt(
                                        IntPtr hdcDest, // handle to destination DC
                                        int nXDest,  // x-coord of destination upper-left corner
                                        int nYDest,  // y-coord of destination upper-left corner
                                        int nWidth,  // width of destination rectangle
                                        int nHeight, // height of destination rectangle
                                        IntPtr hdcSrc,  // handle to source DC
                                        int nXSrc,   // x-coordinate of source upper-left corner
                                        int nYSrc,   // y-coordinate of source upper-left corner
                                        System.Int32 dwRop  // raster operation code
                                        );
        #endregion

        public RectangleTracker(UserControl uc)
        {
            this._uc = uc;
        }

        public void MouseDown(int x, int y)
        {
            _is_tracking = true;

            _mouse_start = new Point(x, y);

            Rectangle r = this._uc.ClientRectangle;

            Point tl = new Point(r.Left, r.Top);
            tl = this._uc.PointToScreen(tl);
            tl = this._uc.Parent.PointToClient(tl);

            Graphics g1 = this._uc.CreateGraphics();
            this._image = new Bitmap(r.Width, r.Height, g1);

            Graphics g2 = Graphics.FromImage(this._image);
            IntPtr dc1 = g1.GetHdc();
            IntPtr dc2 = g2.GetHdc();
            BitBlt(dc2, 0, 0, r.Width, r.Height, dc1, 0, 0, 0x00CC0020 /* dest = source*/);

            // Clean up !!
            g1.ReleaseHdc(dc1);
            g2.ReleaseHdc(dc2);

            _mouse_start.X = x;
            _mouse_start.Y = y;
        }

        public void MouseMoving(int x, int y)
        {
            if (!_is_tracking)
            {
                return;
            }

            if (_pg1 == null)
            {
                _pg1 = this._uc.CreateGraphics();
            }

            if (this._uc.DisplayRectangle.Contains(x, y))
            {
                _mouse_moving = new Point(x, y);

                if (_oldP1 == _oldP2)
                {
                    DrawXorRectangle(_pg1, _mouse_start, _mouse_moving, false);
                }
                else
                {
                    DrawXorRectangle(_pg1, _oldP1, _oldP2, true);
                }
                DrawXorRectangle(_pg1, _mouse_start, _mouse_moving, false);
                _oldP1 = _mouse_start;
                _oldP2 = _mouse_moving;
            }
        }

        public void MouseUp(int x, int y)
        {
            _mouse_moving = new Point(x, y);

            _oldP1 = _oldP2;
            _is_tracking = true;

            _staticTextureBrush = null;
            _staticPenRubout = null;
        }

        private void DrawXorRectangle(Graphics g, Point p1, Point p2, Boolean bRubOut)
        {
            if (!_is_tracking)
            {
                return;
            }

            g.CompositingMode = CompositingMode.SourceOver;

            if (bRubOut && _staticTextureBrush == null && _staticPenRubout == null)
            {
                if (this._image != null)
                {
                    _staticTextureBrush = new TextureBrush(this._image);
                    _staticPenRubout = new Pen(_staticTextureBrush, this._width + 2);
                    // Debug.WriteLine("Creating staticPenRubout");
                }
                else
                {
                    g.Dispose();
                    Debug.WriteLine("Cannot create staticPenRubout");
                }
            }

            if (bRubOut && _staticPenRubout != null && !(p1 == p2))
            {
                float x = p1.X<p2.X ? p1.X : p2.X;
                float y = p1.Y<p2.Y ? p1.Y : p2.Y;
                float width = Math.Abs(p1.X - p2.X);
                float height = Math.Abs(p1.Y - p2.Y);
                //Rectangle rect(x, y, width, height);
                _rect.X = (int)x;
                _rect.Y = (int)y;
                _rect.Width = (int)width;
                _rect.Height = (int)height;
                g.DrawRectangle(_staticPenRubout, x, y, width, height);
                // Debug.WriteLine("		Erase line");
            }
            else
            {
                Pen p = new Pen(this._color, this._width);
                //p.DashStyle = this.DashStyle;

                g.DrawLine(p, _mouse_start, _mouse_moving);
                // Debug.WriteLine("Draw line");
            }

            
        }

        public Rectangle Rect
        {
            get {   return _rect;   }
        }
    }
}
